/* 
 * Author: zhaoYiHang
 * Description: transFile.c用于服务端向用户端发送文件
 * 1.断点续传
 * 2.mmap将文件大小映射入内存
 * 存在问题：
 * 1.off_t 与int 类型的统一
 * 2.小于100M普通传输
 */

#include "threadPool.h"
//结构体train_t用于传输文件的
//1.名字
//2.文件的字节数
//3.文件的内容
//第一个参数是accept之后返回的netfd
//第二个参数是recvOrder.c拆解后的文件名
int transFile(int netfd,char *buf){    
    //声明并初始化一个haveBytes，
    //用来获取服务端发送的已有的字节数
    char haveBytes[1024] = {0};
    //定义length来接火车头
    int length;
    //接收客户端发来的haveBytes
    recvn(netfd, &length, sizeof(length));
    recvn(netfd, haveBytes, length);
    //test
    printf("客户端发来的已有字节数haveBytes：%s\n",haveBytes);
    //2G之内可以，不应该是int应该是off_t
    int haveBytes_int = atoi(haveBytes);
   
    //根据客户端传来的逻辑路径，通过数据库找到
    //文件名和文件的md5
    char bufForSelect[1024];
    //test
    printf("接收到的逻辑路径是%s\n",buf);
    snprintf(bufForSelect, sizeof(bufForSelect), "SELECT * FROM FileTable WHERE path='%s'", buf);
    int qret = mysql_query(mysql,bufForSelect);

    printf("返回的qret=%d\n",qret);
    //是否查到数据库
    if(qret !=0)
    {
        printf("Failed to execute query: %s\n", mysql_error(mysql));
        mysql_close(mysql);
        return 1;
    }
    // 查询成功，获取查询结果
    MYSQL_RES *result = mysql_store_result(mysql);
    if (result == NULL) {
        printf("Failed to get query result: %s\n", mysql_error(mysql));
        mysql_close(mysql);
        return 1;
    }
    //根据路径获取filename，md5
    MYSQL_ROW row;
    //test
    row = mysql_fetch_row(result);

    char buf_filename[4096];
    char md5[4096];
    memcpy(buf_filename,row[1],strlen(row[1])+1);
    memcpy(md5,row[6],strlen(row[6])+1);
    
    
    //声明火车
    train_t train;
    //初始化火车，准备发送文件名
    train.length = strlen(buf_filename);
    //test
    printf("transFile(filename)-----buf=%s \n",buf_filename);
    //将buf里的数据放到train.data里
    memcpy(train.data, buf_filename, train.length);
    //test看一眼data里是不是filename
    printf("transFile(filename)-----train.data=%s \n",train.data);
    //发送文件名字
    send(netfd,&train,sizeof(int)+train.length,MSG_NOSIGNAL);// 发文件的名字
    
    //打开要传给客户端的文件
    char path[256] = "storage/";
    char *path_dir = strcat(path,md5);
    int fd = open(path_dir,O_RDWR);
    
    //为了传文件大小，所以要获取文件的信息
    //声明statbuf结构体来获取文件信息
    struct stat statbuf;
    //fstat参数是文件描述符
    //stat参数是文件的name
    fstat(fd,&statbuf);

    //更新的文件大小
    //statbuf.st_size = statbuf.st_size;
    //----------------
    train.length = sizeof(statbuf.st_size);
    memcpy(train.data,&statbuf.st_size,train.length);
    //printf("transFile(filesize)=%ld \n",statbuf.st_size-haveBytes_int);
    send(netfd,&train,sizeof(int)+train.length,MSG_NOSIGNAL);// 发文件的大小
    char *p = (char *)mmap(NULL,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    ERROR_CHECK(p,MAP_FAILED,"mmap");
    off_t totalsize = haveBytes_int;//记录已经发送的长度
    while(totalsize < statbuf.st_size){
        if(statbuf.st_size - totalsize > 1){
            
            train.length = 1;//剩余未发送的内容超过1000
        }
        else{
            train.length = statbuf.st_size - totalsize;
            //剩余内容不足1000
        }
        sleep(1);
        send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);//发火车头
        send(netfd,p+totalsize,train.length,MSG_NOSIGNAL);//火车车厢在mmap映射区
        //printf("发送文件内容：%s",p+totalsize);
        totalsize += train.length;
    }
    // 补发一个空火车
    train.length = 0;
    printf("transFile End!\n");
    send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);//发火车头
    munmap(p,statbuf.st_size);
    close(fd);
    return 0;
}
